package com.serviceprovider.business.module.admin.role.services.dao.impl;

//~--- non-JDK imports --------------------------------------------------------

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.Authentication;
import org.springframework.security.ConfigAttribute;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.userdetails.hierarchicalroles.RoleHierarchy;
import org.springframework.security.vote.AccessDecisionVoter;

//~--- JDK imports ------------------------------------------------------------

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class DatabaseDrivenRoleVoter extends org.springframework.security.vote.RoleHierarchyVoter {
    private String        actionPrefix = "ACTION_";
    private RoleHierarchy _roleHierarchy;
    private JdbcTemplate  jdbcTemplate;

    public DatabaseDrivenRoleVoter(RoleHierarchy h) {
        super(h);
        this._roleHierarchy = h;
    }

    public String getActionPrefix() {
        return actionPrefix;
    }

    public void setActionPrefix(String actionPrefix) {
        this.actionPrefix = actionPrefix;
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
        Class className = null;

        if (!(object instanceof org.springframework.aop.framework.ReflectiveMethodInvocation)) {
            return super.vote(authentication, object, config);
        } else {
            className =
                ((org.springframework.aop.framework.ReflectiveMethodInvocation) object).getMethod().getDeclaringClass();
        }

        Iterator it = config.getConfigAttributes().iterator();
        String   s  = "";

        // s += authentication.getName()+"class = "+className+" action = ";
        while (it.hasNext()) {
            ConfigAttribute a = (ConfigAttribute) it.next();

            if (a.toString().startsWith(actionPrefix)) {
                String action = a.toString().substring(actionPrefix.length(), a.toString().length());

                s += action;

                List<String> authorizedRoles = getAuthorizedRoles(className.getName(), action);

                /*
                 *  s+=" authorized roles = ";
                 * for (String authorizedRole : authorizedRoles) {
                 * //s+=authorizedRoles.get(i)+",";
                 * }
                 */
                s += ";myAllRoles=[";

                GrantedAuthority[] myAllRoles =
                    _roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());

                for (GrantedAuthority myAllRole1 : myAllRoles) {
                    s += myAllRole1.getAuthority();
                }

                s += "]";

                // if(true){throw new RuntimeException(s);}
                for (String aRole : authorizedRoles) {
                    for (GrantedAuthority myAllRole : myAllRoles) {
                        if (myAllRole.equals(aRole)) {
                            return AccessDecisionVoter.ACCESS_GRANTED;
                        }
                    }
                }
            } else {
                return super.vote(authentication, object, config);
            }
        }

        return AccessDecisionVoter.ACCESS_DENIED;
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return attribute.toString().startsWith(this.actionPrefix) || super.supports(attribute);
    }

//  private String getRole(String email){
//          String sql = "select role from v_users where email = '"+email+"'";
//          Map map =  (Map)getJdbcTemplate().queryForList(sql).get(0);
//          return map.get("role").toString();
//  }
    private List<String> getAuthorizedRoles(String className, String action) {
        List<String> ret = new ArrayList<String>();
        StringBuffer sql =
            new StringBuffer("select r.name from role r, acl_class c, acl_action a, acl_action_apply app where ");

        sql.append("(app.role_id = r.id) and (app.class_id = c.id) and (app.action_id = a.id) and (app.flag = 1) ");
        sql.append("and (a.name = '" + action + "') and (c.class = '" + className + "')");

        List list = getJdbcTemplate().queryForList(sql.toString());

        for (Object obj : list) {
            Map row = (Map) obj;

            ret.add((String) row.get("name"));
        }

        return ret;
    }
}



